package com.opener.web.auth.service.impl;

import com.opener.common.http.NetworkUtils;
import com.opener.common.utils.CookieUtils;
import com.opener.common.utils.Utils;
import com.opener.web.auth.constant.AuthConstants;
import com.opener.web.auth.dao.UserAuthDao;
import com.opener.web.auth.model.UserAuthToken;
import com.opener.web.auth.service.UserAuthService;
import com.sun.org.apache.bcel.internal.generic.IF_ACMPEQ;
import org.apache.commons.codec.digest.DigestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;

/**
 *
 * @author baboy
 * @date 08/12/2016
 */
@Service
public class UserAuthServiceImpl implements UserAuthService {
    private Logger logger = LoggerFactory.getLogger(this.getClass());
//    private static int UID_BITS = 2;
    private static String SEGMENT_LEN_FORMAT = "000";
    private static String UID_LEN_FORMAT = "0000000";
    private static int SALT_BITS = 8;
    private static int CHECK_CODE_BITS = 4;
    private static String UKEY_PREFIX = "AA";

    @Autowired
    protected UserAuthDao userAuthDao;
    @Value("${auth.cookie.expire}")
    protected int expireTimeInSeconds;
    @Value("${auth.concur.num}")
    protected int concurLoginNum;
    @Value("${auth.concur.conf}")
    protected String authConcurConfString;

    private Map<String, Integer> authConcurConf = new HashMap<>();

    private String getPlatformByOs(String os){
        if ("android".equalsIgnoreCase(os) || "ios".equalsIgnoreCase(os)){
            return "app";
        }
        return "other";
    }
    @Override
    public int addAuthToken(UserAuthToken token) {
        return userAuthDao.addAuthToken(token);
    }

    @Override
    public boolean updateAuthToken(UserAuthToken token) {
        return userAuthDao.updateAuthToken(token);
    }
    @PostConstruct
    public void init(){
        if(authConcurConfString != null){
            String[] a = authConcurConfString.split(";");
            for (int i = 0; i < a.length; i++){
                String[] a2 = a[i].split(":");
                if(a2.length == 2){
                    Integer v = Utils.parseInt(a2[1]);
                    if(v != null){
                        authConcurConf.put(a2[0], v);
                    }
                }
            }
        }
    }

    @Override
    public List<UserAuthToken> getAuthTokens(int uid, String domain, String platform) {
        int num = concurLoginNum;
        if(platform != null && authConcurConf.containsKey(platform)){
            num = authConcurConf.get(platform);
        }
        return userAuthDao.getAuthTokens(uid, platform,domain, num);
    }

    @Override
    public UserAuthToken getLastAuthTokenByOs(Integer uid, String os) {
        String platform = getPlatformByOs(os);
        UserAuthToken authToken = userAuthDao.getLastAuthToken(uid, platform);
        return authToken;
    }

    @Override
    public UserAuthToken getAuthTokenByUkey(String ukey) {
        return userAuthDao.getAuthTokenByUkey(ukey);
    }

    @Override
    public UserAuthToken createUserAuthToken(UserAuthToken token) {
        token.setStatus(UserAuthToken.STATUS_LOGIN);

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.add(Calendar.SECOND, expireTimeInSeconds);

        token.setExpireTime(calendar.getTime());
        token.setCreateTime(new Date());

        String ukey = UKeyUtils.createKeyAB(token);
        token.setUkey(ukey);
        addAuthToken(token);
        return token;
    }

    @Override
    public UserAuthToken createUserAuthToken(Long uid,String domain, HttpServletRequest request) {
        String deviceId = getContextParam(request, "deviceId");
        String deviceName = getContextParam(request,"deviceName");
        if (deviceId == null){
            deviceId = request.getHeader("user-agent");
            deviceName = NetworkUtils.getBrowserName(deviceId);
        }
        String os = getContextParam(request, "os");
        String ip = NetworkUtils.getIpAddress(request);
        String platform = getPlatformByOs(os);
        String version = getContextParam(request, "version");
        String osVersion = getContextParam(request, "osVersion");
        UserAuthToken token = new UserAuthToken();
        token.setUid(uid);
        token.setDomain(domain);
        token.setPlatform(platform);
        token.setDeviceName(deviceName);
        token.setDeviceId(deviceId);
        token.setVersion(version);
        token.setOs(os);
        token.setOsVersion(osVersion);
        token.setIp(ip);
        return createUserAuthToken(token);
    }

    @Override
    public UserAuthToken createUserAuthToken(Long uid,  HttpServletRequest request) {
        String domain = request.getHeader("X-Host");
        if (domain == null){
            domain = request.getRemoteHost();
        }
        return createUserAuthToken(uid,domain, request);
    }

    @Override
    public UserAuthToken getCheckedAuthToken(String ukey, String domain, String platform, String deviceId){
        if (ukey == null || ukey.length() == 0){
            return null;
        }
        UserAuthToken existToken = getAuthTokenByUkey(ukey);
        if (existToken != null){
            if (domain != null && !domain.equalsIgnoreCase(existToken.getDomain())){
                return null;
            }
            if (platform != null && !platform.equalsIgnoreCase(existToken.getPlatform())){
                return null;
            }
            if (deviceId != null && !deviceId.equalsIgnoreCase(existToken.getDeviceId())){
                return null;
            }
        }
        return existToken;
    }

    @Override
    public UserAuthToken getCheckedAuthToken(String ukey,String domain, HttpServletRequest request) {
        String deviceId = getContextParam(request, "deviceId");
        String os = getContextParam(request, "os");
        String platform = getPlatformByOs(os);
        return getCheckedAuthToken(ukey,domain, platform,deviceId);
    }

    @Override
    public UserAuthToken getCheckedAuthToken(HttpServletRequest request) {
        String ukey = getContextParam(request, AuthConstants.CookieKey.UKEY );
        String domain = request.getHeader("X-Host");
        return getCheckedAuthToken(ukey, domain, request);
    }

    private String getContextParam(HttpServletRequest request, String k){
        try {
            String v = request.getHeader("X-"+k);
            if(v == null){
                Cookie cookie = CookieUtils.getCookie(request, k);
                if(cookie != null) {
                    v = cookie.getValue();
                }
            }
            if(v == null) {
                v = request.getParameter(k);
            }
            return v;
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public void loginWithCookie( UserAuthToken token,HttpServletResponse response) {
        int cookieMaxAge = (int)(token.getExpireTime().getTime()/1000 - System.currentTimeMillis()/1000);
        CookieUtils.addCookie(response, AuthConstants.CookieKey.UKEY,token.getUkey(),token.getDomain(),null,cookieMaxAge);
        CookieUtils.addCookie(response, AuthConstants.CookieKey.UID,String.valueOf(token.getUid()),token.getDomain(),null,cookieMaxAge);
    }

    @Override
    public void logoutWithCookie(UserAuthToken token,HttpServletResponse response) {

        token.setExpireTime(new Date());
        token.setStatus(UserAuthToken.STATUS_LOGOUT);
        updateAuthToken(token);
        CookieUtils.removeCookie(response, AuthConstants.CookieKey.UKEY, token.getDomain(),null);
        CookieUtils.removeCookie(response, AuthConstants.CookieKey.UID, token.getDomain(),null);
    }

}
